#[macro_use]
extern crate serde_derive;
mod entry;
pub mod logger;
mod tests;

pub use crate::entry::Entry;
pub use crate::logger::Level;
pub use crate::logger::LevelFormat;
pub use crate::logger::LogFormat;
pub use crate::logger::Logger;
pub use crate::logger::TimeFormat;
use lazy_static::lazy_static;
use std::panic;
use std::sync::Mutex;

lazy_static! {
    pub static ref LOGGER: Mutex<Logger> = Mutex::new(Logger::default());
}

// 初始化日志记录器的函数
pub fn init(file_path: String, sync: bool) {
    if let Ok(mut guard) = LOGGER.lock() {
        guard.set_file_output(file_path, sync);
        panic::set_hook(Box::new(|info| {
            YlogPanic!("ylog -> capture panic message: {}", info)
        }));
    }
}

// 设置是否在终端输出日志的函数
pub fn set_enable_term_output(b: bool) {
    if let Ok(mut guard) = LOGGER.lock() {
        guard.set_enable_term_output(b);
    }
}

// 设置是否在终端输出日志的函数
pub fn set_enable_term_color(b: bool) {
    if let Ok(mut guard) = LOGGER.lock() {
        guard.set_enable_term_color(b);
    }
}

// 设置日志级别的函数
pub fn set_log_level(level: Level) {
    if let Ok(mut guard) = LOGGER.lock() {
        guard.set_log_level(level);
    }
}

// 设置时间格式的函数
pub fn set_time_format(format: TimeFormat) {
    if let Ok(mut guard) = LOGGER.lock() {
        guard.set_time_format(format);
    }
}

// 设置是否启用 trace 级别的日志记录的函数
pub fn set_enable_trace(b: bool) {
    if let Ok(mut guard) = LOGGER.lock() {
        guard.set_enable_trace(b);
    }
}

pub fn set_level_format(level_format: LevelFormat) {
    if let Ok(mut guard) = LOGGER.lock() {
        guard.set_level_format(level_format);
    }
}

#[macro_export]
macro_rules! Trace{
    ($($arg:tt)*) => {
        if let Ok(mut lock) = $crate::LOGGER.lock() {
            lock.trace(&format!($($arg)*), concat!(file!()).into(), line!() as usize);
        }
    };
}

#[macro_export]
macro_rules! Debug{
    ($($arg:tt)*) => {
        if let Ok(mut lock) = $crate::LOGGER.lock() {
            lock.debug(&format!($($arg)*), concat!(file!()).into(), line!() as usize);
        }
    };
}

#[macro_export]
macro_rules! Info{
    ($($arg:tt)*) => {
        if let Ok(mut lock) = $crate::LOGGER.lock() {
            lock.info(&format!($($arg)*), concat!(file!()).into(), line!() as usize);
        }
    };
}

#[macro_export]
macro_rules! Warn{
    ($($arg:tt)*) => {
        if let Ok(mut lock) = $crate::LOGGER.lock() {
            lock.warn(&format!($($arg)*), concat!(file!()).into(), line!() as usize);
        }
    };
}

#[macro_export]
macro_rules! Err{
    ($($arg:tt)*) => {
        if let Ok(mut lock) = $crate::LOGGER.lock() {
            lock.error(&format!($($arg)*), concat!(file!()).into(), line!() as usize);
        }
    };
}

#[macro_export]
macro_rules! Crit{
    ($($arg:tt)*) => {
        if let Ok(mut lock) = $crate::LOGGER.lock() {
            lock.crit(&format!($($arg)*), concat!(file!()).into(), line!() as usize);
        }
    };
}

#[macro_export]
macro_rules! Fatal{
    ($($arg:tt)*) => {
        if let Ok(mut lock) = $crate::LOGGER.lock() {
            lock.fatal(&format!($($arg)*), concat!(file!()).into(), line!() as usize);
        }
    };
}

#[macro_export]
macro_rules! YlogPanic{
    ($($arg:tt)*) => {
        if let Ok(mut lock) = $crate::LOGGER.lock() {
            lock.panic(&format!($($arg)*), concat!(file!()).into(), line!() as usize);
            panic!("ylog: fatal log panic, checkout the latest log entry");
        }
    };
}

#[macro_export]
macro_rules! LogN {
    // ($($arg:tt)*) => {
    ($level:expr, $message:literal $(, $arg:tt)*) => {
        if let Ok(mut lock) = $crate::LOGGER.lock() {
            lock.lognum(
                $level,
                &format!($message $(, $arg)*),
                concat!(file!()).into(),
                line!() as usize,
            );
        }
    };
}
